import install, { installModule, resetStoreVM } from "./install";
import ModuleCollection from "./module/module-collection";

class Store {
  constructor(options) {
    // 将选项进行格式化
    this._modules = new ModuleCollection(options);

    this._mutations = Object.create(null);
    this._actions = Object.create(null);
    this._wrappedGetters = Object.create(null);

    // 传入根状态，将所有的子状态都定义在这个根状态
    const state = this._modules.root.state;
    // 存储插件
    this.plugins = options.plugins || [];
    // 存储订阅
    this.subscribes = [];
    // 标识是否开启严格模式
    this.strict = options.strict;
    // 在mutation 中更改，做一个变量标识，如果在变量为true，则表示是在mutations 中更改的，否则就是非法修改
    this._commiting = false;

    // 初始化模块数据
    installModule(this, state, [], this._modules.root);

    // 创造实例 将getters和state 声明到我们的实例上，实现响应式数据的转换
    resetStoreVM(this, state);

    // 执行所有的插件
    this.plugins.forEach(plugin => plugin(this));
  }

  // 当访问store.state 的时候，返回实例上存储的$$state（响应式数据）
  get state() {
    return this._vm._data.$$state;
  }

  // 执行合法修改，只有通过mutation 修改状态的操作才是合法的
  _withCommiting(fn) {
    // this._commiting 为true，标志着是通过mutation 修改的状态
    this._commiting = true;
    // 执行传入的回调
    fn();
    // 重新设置为false，对非法操作进行监听
    this._commiting = false;
  }

  // 执行mutation
  commit = (type, payload) => {
    if (this._mutations[type]) {
      this._mutations[type].forEach(fn => fn.call(this, payload));
    }
  }

  // 执行action，如果是异步的Promise，则维护到Promise.all() 中执行返回
  dispatch = (type, payload) => {
    if (this._actions[type]) {
      // this._actions[type].forEach(fn => fn.call(this, payload));
      const asyncTasks = this._actions[type].map(fn => fn.call(this, payload));

      return Promise.all(asyncTasks)
    }
  }

  // 对于动态添加的模块，重置store
  registerModule(path, module) {
    // 格式化处理新增模块
    this._modules.register(path, module);
    // 重新安装模块，将包装后的模块传入
    installModule(this, this.state, path, module.newModule);
    // 重置当前的实例，保证动态添加的计算属性也生效
    resetStoreVM(this, this.state);
  }

  // 将vuex 中所有的订阅维护到this.subscribes 中
  subscribe(cb) {
    this.subscribes.push(cb);
  }

  // 替换state
  replaceState(state) {
    // 后续动态添加的模块，替换设置state 也是合法的
    this._withCommiting(() => this._vm._data.$$state = state);
  }
}

export default {
  Store,
  install
}

// class Store {
//   constructor(options) {
//     const state = options.state;
//     const getters = options.getters;
//     const mutations = options.mutations;
//     const actions = options.actions;

//     this.getters = {};
//     const computed = {};

//     Object.keys(getters).forEach(getterKey => {
//       computed[getterKey] = () => {
//         // 这里借助vue 的computed 是有缓存的，依赖的值没有发生变化时不会重新执行的
//         return getters[getterKey](state);
//       }

//       // 每次获取getter 的值，就代理到this._vm 的computed 上（响应式 + 依赖缓存）
//       Object.defineProperty(this.getters, getterKey, {
//         get: () => {
//           return this._vm[getterKey];
//         }
//       })
//     })

//     // 利用Vue 将options 的数据进行响应式处理
//     this._vm = new Vue({
//       data: {
//         // 在定义数据的时候，vue 会对带$ 和_ 的数据进行退让，不进行代理，需要通过_data 访问以保证数据的私密性
//         $$state: state
//       },
//       computed
//     })

//     this.mutations = mutations;
//     this.actions = actions;
//   }

//   get state() {
//     return this._vm._data.$$state;
//   }

//   commit = (type, payload) => {
//     this.mutations[type](this.state, payload);
//   }

//   dispatch = (type, payload) => {
//     this.actions[type](this, payload);
//   }
// }
